<script lang="ts" setup>
import { EleResize } from '@/utils/resize.js'
import { selectOptions } from "@/utils/interface/common"
import modelTrainOption from "@/utils/echarts/modelTrain"
import * as d3 from "d3"
import "@/assets/libs/FCNN.js"
import { ElMessage, ElMessageBox } from "element-plus"
let route = useRoute()
let btxt = ref("选择数据集")
let { proxy } = getCurrentInstance()! as any
let modelTrainRefOption = ref(modelTrainOption)
let trainMain = ref()
let startButton = ref(false)
let addDialog = ref(false)
let addDialog2 = ref(false)
let activeValOptions = ref([
  {
    label: "Relu",
    value: "Relu"
  },
  {
    label: "Sigmoid",
    value: "Sigmoid"
  },
  {
    label: "Tanh",
    value: "Tanh"
  },
  {
    label: "LeakyReLU",
    value: "LeakyReLU"
  },

])
let datasetLength = 0;
let form = ref({ nodeCount: 1, active: false, activeVal: "Relu", dropOut: false, dropOutVal: 0.2 })
let commitObj = ref({
  layers: [],
  newFileName: "",
  runName: "",
  description: "",
  epochs: null,
  optimizer: "Adam",
  learnRate: 0.01,
  lossFunction: "MSE",
  winitializer: "GlorotUniform",
  batchSize: 1024,
  testSetRatio: 0.2,
  dataType: "excel", //pg  excel
  filePath: "",
  features: ["转速", "焊速", "下压力"],
  labels: ["屈服强度"],
  randomSeed: 1,
  tableName: "test2",
  useL2: 0,
  scalerType: 'NoScaler',
  setId: 0,
})
let scalerType =
  [
    { label: '不使用', value: 'NoScaler' },
    { label: '最大最小值归一化', value: 'MinMaxScaler' },
    { label: '标准化', value: 'StandardScaler' },
    { label: 'RobustScaler', value: 'RobustScaler' },
    { label: '绝对值最大标准化', value: 'MaxAbsScaler' },
    { label: '由偏分布转正态分布', value: 'PowerTransformer' },
  ]
let tableData = ref()
let selectRow = ref({
  dataName: ""
})
let DatasetName = ref({})
let lossFuncOptions: Ref<selectOptions[]> = ref([
  { value: "MSE", label: "MSE" },
  { value: "MAE", label: "MAE" },
  { value: "SmoothL1Loss", label: "SmoothL1Loss" },
  { value: "KLDivLoss", label: "KLDivLoss" }
])
let initFuncOptions: Ref<selectOptions[]> = ref([
  { value: "GlorotUniform", label: "[Xavier均匀分布:GlorotUniform]" },
  { value: "GlorotNormal", label: "[Xavier正态分布:GlorotNormal" },
  { value: "GaussianNormal", "label": "[正态高斯分布:GaussianNormal]" },
  { value: "Uniform", "label": "[均匀分布:Uniform]" },
  { value: "KaimingUniform", "label": "[Kaiming均匀分布:KaimingUniform]" },
  { value: "KaimingNormal", "label": "[Kaiming正态分布:KaimingNormal]" },
  { value: "Orthogonal", "label": "[正交矩阵初始化:Orthogonal]" },
  { value: "Sparse", "label": "[稀疏矩阵初始化(50%):Sparse]" }
])
let optimizer: Ref<selectOptions[]> = ref([
  { value: "Adam", label: "Adam" },
  { value: "Nadam", label: "Nadam" },
  { value: "SGD", label: "SGD" },
  { value: "RMSprop", label: "RMSprop" },
  { value: "Adagrad", label: "Adagrad" },
  { value: "Adamax", label: "Adamax" }
])

let tableRef1 = ref()
let gridData = ref([])
let dialogTableVisible = ref(false)
let inputNode = ref(3)
let outputNode = ref(1)
let hiddenLayer = ref([] as any)
let betweenNodesInLayer = [5, 5, 5]
let checkedVal = ref(true)
let checkedInput = ref([] as any)
let runningId: any = null
let testFlag = false
let timer: any = null;
let dataSetName = ref('')
const rules = ref({} as any)
const queryParams = ref({
  dataName: '',
  dataThickness: '',
  newFileName: '',
  description: ''
})
let currentPage = ref(1)
let pageSize = ref(4)
let size = 'default'
let total = ref(0)
let params = {
  dataName: '',
  dataThickness: '',
  newFileName: '',
  description: '',
  pageNo: 1,
  pageSize: 4,
  isAsc: false,
  orderBy: "createTime"
}
// 处理神经元节点的layers
function handleLayers(layer: any) {
  let tmp = [] as any
  if (layer.length > 0) {
    // 表示有添加层
    layer.forEach(
      (l: { num: number; active: { flag: boolean; val: string }; dropout: { flag: boolean; val: string } }, i) => {
        if (i == 0 && layer.length > 1) { // 第一个，但不是最后一个，
          // 第一个
          tmp.push(
            {
              netType: "linear",
              inputDim: inputNode.value,
              outputDim: l.num
            },
          )
          if (l.active.flag) {
            tmp.push(
              {
                netType: "active_layer",
                type: l.active.val
              }
            )
          }
          if (l.dropout.flag) {
            tmp.push(
              {
                netType: "dropout",
                p: l.dropout.val
              }
            )
          }
        }
        else if (i == 0 && layer.length == 1) { // layer length == 1 第一个也是最后一个
          tmp.push(
            {
              netType: "linear",
              inputDim: inputNode.value,
              outputDim: l.num
            },
          )
          if (l.active.flag) {
            tmp.push(
              {
                netType: "active_layer",
                type: l.active.val
              }
            )
          }
          if (l.dropout.flag) {
            tmp.push(
              {
                netType: "dropout",
                p: l.dropout.val
              }
            )
          }
          tmp.push(
            {
              netType: "linear",
              inputDim: l.num,
              outputDim: outputNode.value
            }
          )
        }
        else if (i == layer.length - 1 && layer.length > 1) {
          tmp.push(
            {
              netType: "linear",
              inputDim: layer[i - 1].num,
              outputDim: l.num
            },
          )
          if (l.active.flag) {
            tmp.push(
              {
                netType: "active_layer",
                type: l.active.val
              }
            )
          }
          if (l.dropout.flag) {
            tmp.push(
              {
                netType: "dropout",
                p: l.dropout.val
              }
            )
          }
          tmp.push({
            netType: "linear",
            inputDim: l.num,
            outputDim: outputNode.value
          })
        }
        else {
          tmp.push(
            {
              netType: "linear",
              inputDim: layer[i - 1].num,
              outputDim: l.num
            },
          )
          if (l.active.flag) {
            tmp.push(
              {
                netType: "active_layer",
                type: l.active.val
              }
            )
          }
          if (l.dropout.flag) {
            tmp.push(
              {
                netType: "dropout",
                p: l.dropout.val
              }
            )
          }
        }
      }
    )
    commitObj.value.layers = tmp
  }
}

//重新渲染神经元网络组建
// fcnn.js  文档 https://github.com/alexlenail/NN-SVG/wiki/NN-SVG-API#1-fcnn
function reRenderSvg() {
  let svg = document.querySelector("#graph-container>svg")
  let fcnn = window.FCNN(d3)
  let numArr = [] as Number[]
  for (let i = 0; i < hiddenLayer.value.length; i++) {
    numArr.push(hiddenLayer.value[i].num)
  }
  handleLayers(hiddenLayer.value)
  let architecture = [inputNode.value, ...numArr, outputNode.value]
  if (architecture.length < 8) {
    svg?.parentNode?.removeChild(svg)
    fcnn.redraw({ architecture_: architecture })
    fcnn.redistribute({ betweenNodesInLayer_: Array.from(architecture).fill(5) })
  } else {
    setTimeout(() => {
      let svg = document.querySelectorAll("#graph-container>svg")
      if (svg.length > 1) {
        // 这里重新渲染之前需要移除掉原来的svg
        [...svg].forEach((s) => {
          let g = s.querySelector("g");
          if (g.children.length == 0) {
            s?.parentNode?.removeChild(s)
          }
        })
      }
    }, 1);

  }
}

const inputLayerAdd = () => {
  addDialog.value = true
}

const sureAdd = () => {
  ElMessage({
    type: "success",
    message: `添加成功`
  })
  hiddenLayer.value.push({
    hash: Math.random().toFixed(9),
    num: Number(form.value.nodeCount),
    active: { flag: form.value.active, val: form.value.activeVal },
    dropout: { flag: form.value.dropOut, val: form.value.dropOutVal }
  })
  // console.log(hiddenLayer.value)
  betweenNodesInLayer.push(5)
  reRenderSvg()
  addDialog.value = false
  form.value.nodeCount = 1
  form.value.active = false
  form.value.dropOut = false
}

const inputLayerMinus = (rows) => {
  addDialog2.value = true;
}
const sureMinus = (rows) => {
  console.log(rows, hiddenLayer.value)
  rows.forEach((r) => {
    let index = hiddenLayer.value.findIndex((rr) => {
      return rr.hash == r.hash
    })
    if (index > -1) {
      hiddenLayer.value.splice(index, 1)
    }
  })
  addDialog2.value = false;
  reRenderSvg()
}

const deleteData = () => {
  let rows = tableRef1.value?.getSelectionRows()
  if (rows.length === 0) {
    ElMessage({
      message: "请选择要删除的数据",
      type: "error",
    })
    return
  }
  ElMessageBox.confirm("确定删除选中的层吗？", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      sureMinus(rows)
    })
    .catch(() => { ElMessage.error('出错了！！！') })
}

function test(d3: any, architecture?: any, betweenNodesInLayer?: any) {
  let fcnn = window.FCNN(d3)
  // 渲染神经元网络，redraw 传入一个数组  ，每个元素代表每一层的神经元的个数
  fcnn.redraw({ architecture_: [inputNode.value, 0, outputNode.value] })
  fcnn.redistribute({ betweenNodesInLayer_: [5, 5, 5] })
}

const resetForm = () => {
  queryParams.value.dataName = ""
  queryParams.value.dataThickness = ""
  queryParams.value.newFileName = ""
  queryParams.value.description = ""
}

const query = () => {
  selectDataSet(params)
}
const handleCurrentChange = (e) => {
  params.pageNo = e
  selectDataSet(params)
}

// 选择数据集
const selectDataSet = (params) => {
  dialogTableVisible.value = true;
  checkedVal.value = true;
  params.dataName = queryParams.value.dataName
  params.dataThickness = queryParams.value.dataThickness
  params.newFileName = queryParams.value.newFileName
  params.description = queryParams.value.description
  params.pageNo = currentPage.value
  params.pageSize = pageSize.value
  params.isAsc = false
  params.orderBy = 'createTime'
  const url = "/admin-api/wpes/dataSet/page"
  proxy.$http.get(url, {
    params
  }).then((v: any) => {
    if (v.data.code == 0) {
      gridData.value = v.data.data.list
      total.value = v.data.data.total
      if (checkedInput.value.length == 0) {
        v.data.data.list.forEach((value: any) => {
          checkedInput.value.push({ input: [], output: [] })
        })
      } else if (checkedInput.value.length < v.data.data.list.length) {
        /* 如果 新增数据集， 训练页面没刷新时，此时页面已渲染的数据集数目和实际数据库、接口的数目对不上，需要插入新增数据 */
        for (let j = 0; j < v.data.data.list.length - checkedInput.value.length; j++) {
          checkedInput.value.push({ input: [], output: [] })
        }
      }
    }
  })
}

const getClickRow = (row: any) => {
  commitObj.value.filePath = row.filePath
  datasetLength = row.dataSize
  let index = gridData.value.findIndex((i: any) => {
    return i.id === row.id
  })
  commitObj.value.features = []
  commitObj.value.labels = []
  commitObj.value.features = checkedInput.value[index].input;
  commitObj.value.labels = checkedInput.value[index].output;
  inputNode.value = checkedInput.value[index].input.length
  outputNode.value = checkedInput.value[index].output.length
  dialogTableVisible.value = false
  dataSetName.value = row.dataName
  commitObj.value.newFileName = row.newFileName
  commitObj.value.setId = row.id
  ElMessage.success('已选择数据集')
  btxt.value = '已选择数据集:' + dataSetName.value
}

const flexColumnWidth = (str, arr1, flag = 'max') => {
  // str为该列的字段名(传字符串);tableData为该表格的数据源(传变量);
  // flag为可选值，可不传该参数,传参时可选'max'或'equal',默认为'max'
  // flag为'max'则设置列宽适配该列中最长的内容,flag为'equal'则设置列宽适配该列中第一行内容的长度。
  str = str + ''
  let columnContent = ''
  if (!arr1 || !arr1.length || arr1.length === 0 || arr1 === undefined) {
    return
  }
  if (!str || !str.length || str.length === 0 || str === undefined) {
    return
  }
  if (flag === 'equal') {
    // 获取该列中第一个不为空的数据(内容)
    for (let i = 0; i < arr1.length; i++) {
      if (arr1[i][str].length > 0) {
        // console.log('该列数据[0]:', arr1[0][str])
        columnContent = arr1[i][str]
        break
      }
    }
  } else {
    // 获取该列中最长的数据(内容)
    let index = 0
    for (let i = 0; i < arr1.length; i++) {
      if (arr1[i][str] === null) {
        return
      }
      const now_temp = arr1[i][str] + ''
      const max_temp = arr1[index][str] + ''
      if (now_temp.length > max_temp.length) {
        index = i
      }
    }
    columnContent = arr1[index][str]
  }
  // console.log(columnContent)
  // console.log('该列数据[i]:', columnContent)
  // 以下分配的单位长度可根据实际需求进行调整
  let flexWidth = 0
  for (const char of columnContent + '') {
    if ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z')) {
      // 如果是英文字符，为字符分配8个单位宽度
      flexWidth += 8
    } else if (char >= '\u4e00' && char <= '\u9fa5') {
      // 如果是中文字符，为字符分配15个单位宽度
      flexWidth += 15
    } else {
      // 其他种类字符，为字符分配8个单位宽度
      flexWidth += 9
    }
  }
  if (flexWidth < 80) {
    // 设置最小宽度
    flexWidth = 80
  }
  // if (flexWidth > 250) {
  //   // 设置最大宽度
  //   flexWidth = 250
  // }
  // console.log(flexWidth)
  return flexWidth + 'px'
}

const handleNodeNum = (val: string) => {
  form.value.nodeCount = Math.ceil(Number(val))
}

const hanledropOutVal = (val: string) => {
  if (Number(val) < 0) {
    form.value.dropOutVal = 0
  }
  if (Number(val) > 1) {
    form.value.dropOutVal = 1.0
  }
}

function train(id?) {
  console.log(id)
  startButton.value = true
  if (id) {
    ElMessage.info({
      message: '当下继续未完成的训练',
      duration: 1888
    })
    let url = '/admin-api/wpes/runResult/running/get';
    //let url = '/admin-api/wpes/model/bpnnTrainAsync';
    runningId = id
    let params = {
      id: runningId
    }
    timer = setInterval(() => {
      proxy.$http.get(url, { params }).then((vv) => {
        if (vv.data.code == 401) { // 表示需要验证token

        }
        if (vv.data.data.status == 'FINISHED') {
          startButton.value = false;
          clearInterval(timer)
          runningId = null
          timer = null
          ElMessage.success('已完成训练')
          commitObj.value.features = [];
          commitObj.value.labels = [];
        } else if (vv.data.data.status == 'WAITING') {
          ElMessage.info({
            message: '正在等待分配硬件资源,稍后完成训练',
            duration: 2222
          })
        } else if (vv.data.data.status == 'RUNNING') {
          ElMessage.info({
            message: '正在训练中,请稍后',
            duration: 2222
          })
          let p1 = JSON.parse(vv.data.data.trainLossList) ?? []
          let p2 = JSON.parse(vv.data.data.testLossList) ?? []
          modelTrainRefOption.value.series[0].data = p1
          modelTrainRefOption.value.series[1].data = p2
          let t = [] as any
          p1.forEach((v, i) => {
            t.push(i + 1)
          })
          modelTrainRefOption.value.xAxis.data = t
          proxy.trainMainInstance && proxy.trainMainInstance.setOption(modelTrainRefOption.value)
        } else if (vv.data.data.status == 'ERROR') {
          startButton.value = false;
          clearInterval(timer)
          runningId = null
          timer = null
          ElMessage.error('训练出错了1' + JSON.stringify(vv.data.data.errorMsg))
        }
        else if (vv.data.data.status == 'STOPPED') {
          startButton.value = false;
          clearInterval(timer)
          runningId = null
          timer = null
          ElMessage.error('本次训练已停止')
        }
        else {
          let p1 = JSON.parse(vv.data.data.trainLossList) ?? []
          let p2 = JSON.parse(vv.data.data.testLossList) ?? []
          modelTrainRefOption.value.series[0].data = p1
          modelTrainRefOption.value.series[1].data = p2
          let t = [] as any
          p1.forEach((v, i) => {
            t.push(i + 1)
          })
          modelTrainRefOption.value.xAxis.data = t
          proxy.trainMainInstance && proxy.trainMainInstance.setOption(modelTrainRefOption.value)
        }
      }).catch(e => {
        console.log(e)
        ElMessage.error('训练出错了2' + JSON.stringify(e))
        startButton.value = false;
        clearInterval(timer)
        runningId = null
        timer = null
      })
      return;
    }, 5555)

  } else {
    let url = '/admin-api/wpes/model/bpnnTrainAsync';
    proxy.$http
      .post(url, commitObj.value)
      .then((v: any) => {
        console.log(v)
        if (v.data.code == 0) {
          runningId = id ?? v.data.data
          timer = setInterval(() => {
            let url = "/admin-api/wpes/runResult/running/get"
            let params = {
              id: runningId
            }
            proxy.$http.get(url, { params }).then((vv) => {
              if (vv && vv.data) {
                if (vv.data.data.status == 'FINISHED') {
                  startButton.value = false;
                  clearInterval(timer)
                  runningId = null
                  timer = null
                  ElMessage.success('已完成训练')
                  commitObj.value.features = [];
                  commitObj.value.labels = [];
                } else if (vv.data.data.status == 'WAITING') {
                  ElMessage.info({
                    message: '正在等待分配硬件资源,稍后完成训练',
                    duration: 2222
                  })
                } else if (vv.data.data.status == 'RUNNING') {
                  ElMessage.info({
                    message: '正在训练中,请稍后',
                    duration: 2222
                  })
                  let p1 = JSON.parse(vv.data.data.trainLossList) ?? []
                  let p2 = JSON.parse(vv.data.data.testLossList) ?? []
                  modelTrainRefOption.value.series[0].data = p1
                  modelTrainRefOption.value.series[1].data = p2
                  let t = [] as any
                  p1.forEach((v, i) => {
                    t.push(i + 1)
                  })
                  modelTrainRefOption.value.xAxis.data = t
                  proxy.trainMainInstance && proxy.trainMainInstance.setOption(modelTrainRefOption.value)
                } else if (vv.data.data.status == 'ERROR') {
                  startButton.value = false;
                  clearInterval(timer)
                  runningId = null
                  timer = null
                  ElMessage.error('训练出错了3' + JSON.stringify(vv.data.data.errorMsg))
                }
                else if (vv.data.data.status == 'STOPPED') {
                  startButton.value = false;
                  clearInterval(timer)
                  runningId = null
                  timer = null
                  ElMessage.error('本次训练已停止')
                }
                else {
                  let p1 = JSON.parse(vv.data.data.trainLossList) ?? []
                  let p2 = JSON.parse(vv.data.data.testLossList) ?? []
                  modelTrainRefOption.value.series[0].data = p1
                  modelTrainRefOption.value.series[1].data = p2
                  let t = [] as any
                  p1.forEach((v, i) => {
                    t.push(i + 1)
                  })
                  modelTrainRefOption.value.xAxis.data = t
                  proxy.trainMainInstance && proxy.trainMainInstance.setOption(modelTrainRefOption.value)
                }
              } else { // 说明401了
                console.log(vv, '401')
              }

            }).catch(e => {
              console.log(e)
              ElMessage.error('训练出错了4' + JSON.stringify(e))
              startButton.value = false;
              clearInterval(timer)
              runningId = null
              timer = null
            })
          }, 5555)
        } else {
          //  error
          ElMessage.error(v.data.msg + 'error')
          startButton.value = false
        }
      })
  }

}

// 开始训练
const go = () => {
  if (testFlag) {
    // 一键测试
    commitObj.value.batchSize = 22
    commitObj.value.epochs = 222
    commitObj.value.useL2 = 1.0
    commitObj.value.learnRate = 0.0002
    commitObj.value.description = 'yijianceshi'
    commitObj.value.runName = 'yijianceshi'
  }
  if (commitObj.value.filePath == '' || commitObj.value.batchSize == '' || commitObj.value.batchSize == null
    || commitObj.value.runName == '' || commitObj.value.epochs == '' || commitObj.value.epochs == null
    || commitObj.value.layers.length == 0
  ) {
    ElMessage.warning('请选择必要参数后再训练！！！')
    return
  } else if (datasetLength * commitObj.value.testSetRatio < 1 || datasetLength * (1 - commitObj.value.testSetRatio) < 1) {
    ElMessage.warning('请确保测试集和训练集至少有1条样本！')
    return
  }
  train()
}

// 停止训练
const stopTrain = () => {
  ElMessageBox.confirm('确定终止训练吗？', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
  }).then((v) => {
    let params = {
      id: runningId
    }
    clearInterval(timer)
    ElMessage.error('进程终止中...')
    startButton.value = false
    proxy.$http.put(`/admin-api/wpes/model/stop`, null, { params }).then((v) => {
      console.log(v)
      if (v.data.data || v.data.code * 1 == 1000) {
        clearInterval(timer)
        runningId = null
        timer = null
        startButton.value = false
        ElMessage.success('已终止训练')
      } else if (v.data.code * 1 == 1004) {
        clearInterval(timer)
        runningId = null
        timer = null
        startButton.value = false
        ElMessage.error('进程终止中...')
      }
    }).finally(() => {
      clearInterval(timer)
      runningId = null
      timer = null
      startButton.value = false
    })

  }).catch(e => console.log(e))
}

onBeforeRouteLeave((to, from, next) => {
  if (startButton.value == true) {
    ElMessageBox.confirm("当前训练还在进行，是否离开?", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    })
      .then(() => {
        clearInterval(timer)
        startButton.value = false
        next(to);
      })
  } else {
    next();
  }
})

//输入框监听change事件，再绑定页面标签关闭事件
const runNameChange = (e) => {
  window.onbeforeunload = function (event) {
    if (startButton.value = true) {
      clearInterval(timer)
      startButton.value = false
      // 无法用confirm 必须return 且文字无法修改  confirm('您编辑的信息尚未保存，您确定要离开吗？')
      return "您编辑的信息尚未保存，您确定要离开吗？"; //这里内容不会显示在提示框，为了增加语义化。
    }
  };
}

//
function processArray(data) {
  let newArr = [];
  for (let i = 0; i < data.length; i++) {
    let element = data[i];
    if (i === 0) {
      if (element.input_dim !== null) newArr.push(element.input_dim);
      if (element.output_dim !== null) newArr.push(element.output_dim);
      hiddenLayer.value.push({
        hash: Math.random().toFixed(9),
        num: Number(element.output_dim),
        active: { flag: data[1].net_type == "active_layer" ? true : false, val: data[1].net_type == "active_layer" ? data[1].type : null },
        dropout: { flag: data[2].net_type == "dropout" ? true : false, val: data[2].net_type == "dropout" ? data[2].p : null }
      })
    } else if (i === data.length - 1) {
      if (element.output_dim !== null) newArr.push(element.output_dim);
    }
    else {
      if (i + 1 < data.length - 1 && data[i + 1].net_type == 'active_layer') {
        let obj: any = {
          hash: Math.random().toFixed(9),
          num: Number(element.output_dim),
          active: { flag: true, val: data[i + 1].type },
          dropout: { flag: false, val: null },
        }
        if (i + 2 < data.length - 1 && data[i + 2].net_type == "dropout") {
          obj.dropout = { flag: true, val: data[i + 2].p }
        }
        hiddenLayer.value.push(obj)
      } else {
        if (element.net_type == "linear") {
          hiddenLayer.value.push({
            hash: Math.random().toFixed(9),
            num: Number(element.output_dim),
            active: { flag: false, val: null },
            dropout: { flag: false, val: null }
          })
        }

      }
      if (element.output_dim !== null) newArr.push(element.output_dim);
    }
  }
  return newArr;
}

const handleSvg = (layers: any) => {
  setTimeout(() => {
    let svg = document.querySelector("#graph-container>svg")
    svg?.parentNode?.removeChild(svg)
    let numArr = processArray(layers)
    // console.log(layers, numArr)
    let fcnn = window.FCNN(d3)
    fcnn.redraw({ architecture_: numArr })
    fcnn.redistribute({ betweenNodesInLayer_: Array.from(numArr).fill(5) })
  }, 111);

}

function camel(data: any) {
  if (typeof data != 'object' || !data) return data
  if (Array.isArray(data)) {
    return data.map(item => camel(item))
  }

  const newData = {}
  for (let key in data) {
    let newKey = key.replace(/_([a-z])/g, (p, m) => m.toUpperCase())
    newData[newKey] = camel(data[key])
  }
  return newData
}

// 如果是模型管理页，running状态跳转，则继续上次的
const continueGo = (row: any) => {
  let netConfig = JSON.parse(row.netConfig)
  Object.assign(commitObj.value, netConfig)
  commitObj.value = camel(commitObj.value)
  inputNode.value = netConfig.features.length
  outputNode.value = netConfig.labels.length
  handleSvg(netConfig.layers)
  runningId = row.id
  train(runningId)
}


onMounted(() => {
  let query = route.query
  if (query.rowData) {
    //如果存在，则是running，直接开始继续上次的训练
    let rowData = JSON.parse(query.rowData as string)
    console.log(rowData)
    continueGo(rowData)
  }
  if (trainMain.value) {
    let trainMainInstance = proxy!.$echarts.init(trainMain.value)
    // 自适应
    var listener = function () {
      trainMainInstance.resize()
    }
    EleResize.on(trainMain.value, listener)
    proxy.trainMainInstance = trainMainInstance
    trainMainInstance && trainMainInstance.setOption(modelTrainRefOption.value)
  }
  test(d3)
})

onUnmounted(() => {

})
</script>

<template>
  <div class="css_cx overflow-hidden" h-full w-full>
    <div class="css_cxc !w-full">
      <div class="inputWrap w-[85%] flex flex-row justify-evenly  -ml-2">
        <el-form :inline="true" :model="DatasetName" :data="tableData" style="margin: 20px 0" class="demo-form-inline">
          <div class="css_tite">
            {{ selectRow.dataName ? "" + selectRow.dataName : "" }}
          </div>
          <el-form-item label="" style="">
            <div class="css_slest">
              <el-button @click="selectDataSet" type="primary" class="">
                {{ btxt }} <em class=" text-red-800 text-2xl flex mt-1.5">*</em>
              </el-button>
              <el-dialog width="1200" v-model="dialogTableVisible" title="请双击选择数据集">
                <div class="search">
                  <el-form :inline="true" :model="DatasetName" :data="tableData" style="margin: 20px 10px"
                    class="demo-form-inline" :rules="rules" ref="DatasetName">
                    <el-form-item class="!mr-5" label="板材型号：" prop="dataName">
                      <el-input style="width: 130px" :maxlength="15" v-model="queryParams.dataName"
                        placeholder="请输入板材型号：" />
                    </el-form-item>
                    <el-form-item class="!mr-5" label="板材厚度(mm)：" prop="dataThickness">
                      <el-input type="number" style="width: 130px" v-model="queryParams.dataThickness" :maxlength="15"
                        placeholder="请输入板材厚度：" />
                    </el-form-item>
                    <el-form-item class="!mr-5" label="数据集名称：">
                      <el-input style="width: 130px" v-model="queryParams.newFileName" :maxlength="15"
                        placeholder="请输入数据集：" />
                    </el-form-item>
                    <el-form-item class="!mr-5" label="描述：">
                      <el-input style="width: 130px" v-model="queryParams.description" :maxlength="15"
                        placeholder="请输入描述：" />
                    </el-form-item>
                    <!-- 选择文件输入框 -->

                    <el-form-item>
                      <el-button class="" type="primary" @click="query">查询</el-button>
                      <el-button class="" type="primary" @click="resetForm">重置</el-button>
                    </el-form-item>
                  </el-form>

                </div>
                <el-table height="500" empty-text="暂无数据，请关闭窗口后重试！" :data="gridData" @row-dblclick="getClickRow">
                  <el-table-column sortable :width="flexColumnWidth('id', gridData)" align="center" property="id"
                    label="Id" />
                  <el-table-column sortable :width="flexColumnWidth('createTime', gridData)" align="center"
                    property="createTime" label="创建日期" />
                  <el-table-column :width="flexColumnWidth('dataName', gridData)" align="center" property="dataName"
                    label="板材型号" />
                  <el-table-column :width="flexColumnWidth('dataThickness', gridData)" align="center"
                    property="dataThickness" label="板材厚度" />
                  <el-table-column width="105" align="center" property="dataSize" label="数据集数量" />
                  <el-table-column width="200" align="center" property="inputParamNames" label="输入参数">
                    <template #default="scope">
                      <div class="">
                        <el-checkbox-group
                          style="display: flex;flex-direction: column; align-items: center; justify-content: center;"
                          v-model="checkedInput[scope.$index].input" @change="">
                          <el-checkbox class="w-full flex justify-center" :checked="checkedVal"
                            v-for="(i, index) in scope.row.inputParamNames" :key="index" :label="i">
                            {{ i }}
                          </el-checkbox>
                        </el-checkbox-group>
                      </div>
                    </template>
                  </el-table-column>
                  <el-table-column width="200" align="center" property="outParamNames" label="输出参数">
                    <template #default="scope">
                      <div class="">
                        <el-checkbox-group style="display: flex;flex-direction: column; align-items: center"
                          v-model="checkedInput[scope.$index].output" @change="">
                          <el-checkbox class="w-full flex justify-center" :checked="checkedVal"
                            v-for="(o, index) in scope.row.outParamNames" :key="index" :label="o">
                            {{ o }}
                          </el-checkbox>
                        </el-checkbox-group>
                      </div>
                    </template>
                  </el-table-column>
                  <el-table-column :width="flexColumnWidth('newFileName', gridData)" align="center"
                    property="newFileName" label="数据集" />

                  <el-table-column :width="flexColumnWidth('description', gridData)" align="center"
                    property="description" label="描述" />
                </el-table>
                <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :size="size"
                  :disabled="false" :background="true" layout="prev, pager, next, jumper" :total="total"
                  @current-change="handleCurrentChange" />
                <!-- <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :size="size"
                  :disabled="false" :background="true" layout="prev, pager, next, jumper" :total="total"
                  @current-change="handleCurrentChange" /> -->
              </el-dialog>
            </div>
          </el-form-item>
        </el-form>
        <!-- <div class="flex items-center" v-if="dataSetName !== ''">已选择数据集:{{ dataSetName }}</div> -->
        <div class="css_cxcsq">
          <p class="Selectortitle">测试集的比例</p>
          <el-input-number class="" size="small" v-model="commitObj.testSetRatio" :precision="2" :step="0.01" :max="1"
            :min="0.01" />
        </div>
        <div class="css_cxcsq">
          <p class="Selectortitle">随机种子</p>
          <el-input-number class="" size="small" v-model="commitObj.randomSeed" :precision="0" :step="1" :min="0" />
        </div>

        <div class="flex  flex-col justify-center items-center">
          <div class="bt  flex justify-center h-4 ">分批训练时每批样本数量<em class=" text-red-800 text-xl">*</em></div>
          <div class="css_cxcc pt-1 w-42 h-8">
            <el-input type="number" min="0" v-model="commitObj.batchSize"></el-input>
          </div>
        </div>

        <div class="flex flex-col justify-center items-center ">
          <div class="bt">数据预处理-特征转换</div>
          <div class="css_cxcc pt-2">
            <el-select class="!w-42" v-model="commitObj.scalerType" size="small" placeholder="请选择">
              <el-option v-for="item in scalerType" :key="item.label" :label="item.label" :value="item.value">
              </el-option>
            </el-select>
          </div>
        </div>
        <div class="css_cxcsq mr-8">
          <p class="Selectortitle text-center">神经元权重初始化方法</p>
          <el-select class="autoWidth" v-model="commitObj.winitializer" size="small" placeholder="请选择">
            <template #prefix>
              <span>{{ initFuncOptions.find(s => s.value == commitObj.winitializer)?.label }}</span>
            </template>
            <el-option v-for="item in initFuncOptions" :key="item.label" :label="item.label" :value="item.value">
            </el-option>
          </el-select>
        </div>
        <div class="css_cxcsq">
          <p class="Selectortitle">损失函数</p>
          <el-select v-model="commitObj.lossFunction" size="small" placeholder="请选择">
            <el-option v-for="item in lossFuncOptions" :key="item.label" :label="item.label" :value="item.value">
            </el-option>
          </el-select>
        </div>
      </div>

    </div>

    <div class="css_cont w-full !shrink-0 box-border ">
      <div class="w-[85%] flex flex-row justify-evenly  -ml-3">
        <div class="flex flex-col justify-center items-center ">
          <div class="bt">每层L2正则项的权重</div>
          <div class="css_cxcc pt-2">
            <el-input-number class="" size="small" v-model="commitObj.useL2" :precision="3" :step="0.1" :max="10000"
              :min="0" />
          </div>
        </div>
        <div class="css_cxcsq">
          <p class="Selectortitle">优化器</p>
          <el-select v-model="commitObj.optimizer" size="small" placeholder="请选择">
            <el-option v-for="item in optimizer" :key="item.label" :label="item.label" :value="item.value"> </el-option>
          </el-select>
        </div>

        <div class="css_cxcsq">
          <p class="Selectortitle">学习率</p>
          <el-input-number class="" size="small" v-model="commitObj.learnRate" :precision="4" :step="0.0001" :max="1"
            :min="0" />
        </div>

        <div class="css_cxcsq flex-col justify-center items-center !gap-0">
          <div class="Selectortitle flex flex-row">最大迭代次数<em class=" text-red-800 text-xl">*</em></div>
          <el-input class="" size="small" type="number" :maxlength="5" v-model="commitObj.epochs"
            placeholder="请输迭代次数：" />
        </div>
        <div class="flex  flex-col justify-center items-center !gap-0 !shrink-0 box-border">
          <div class="bt flex flex-row !shrink-0 box-border ">训练名称<em
              class=" inline-block text-red-800 text-xl  ">*</em>
          </div>
          <div class="css_cxcc">
            <el-input v-model="commitObj.runName" @change="runNameChange"></el-input>
          </div>
        </div>
        <div class="flex  flex-col justify-center items-center gap-2">
          <div class="bt">训练描述</div>
          <div class="css_cxcc">
            <el-input v-model="commitObj.description"></el-input>
          </div>
        </div>
      </div>

      <div class=" ml-auto mt-5 mr-6 ">
        <el-button size="small" style="border: 1px solid #6fbbff; border-radius: 8px; border-radius: 8px" @click="go"
          type="primary" :disabled="startButton" plain round>
          <template v-if="startButton">正在训练...</template>
          <template v-else>开始</template>
        </el-button>
        <el-button size="small" v-if="startButton"
          style="border: 1px solid #6fbbff; border-radius: 8px; border-radius: 8px" @click="stopTrain" type="primary"
          plain round>
          停止训练
        </el-button>
        <!-- <el-button size="small" v-if="testFlag"
          style="border: 1px solid #6fbbff; border-radius: 8px; border-radius: 8px" @click="stopTrain" type="primary"
          plain round>
          一键测试
        </el-button> -->
      </div>
    </div>
    <div class="css_span1">
      <div style="margin-left: 45px">隐藏层<em class=" text-red-800 text-xl">*</em></div>
      <div class="css_jiajian !ml-22">
        <img cursor-pointer @click="inputLayerAdd" src="../../icons/add.png" />
        <img cursor-pointer @click="inputLayerMinus" src="../../icons/minus.png" />
      </div>
      <el-dialog v-model="addDialog" title="添加">
        <el-form :model="form">
          <el-form-item label="输入隐藏层节点个数">
            <el-input class="!w-21" type="number" autofocus @change="handleNodeNum" min="1" step="1"
              v-model="form.nodeCount" autocomplete="off" />
          </el-form-item>
          <el-form-item label="">
            <div>
              <label class="mr-5">是否启用激活层</label>
              <el-switch v-model="form.active" />
            </div>
          </el-form-item>
          <el-form-item label="">
            <div>
              <label class="mr-5">激活层参数</label>
              <el-select :disabled="!form.active" v-model="form.activeVal" size="small" placeholder="请选择">
                <el-option v-for="item in activeValOptions" :key="item.label" :label="item.label" :value="item.value">
                </el-option>
              </el-select>
            </div>
          </el-form-item>
          <el-form-item label="">
            <div class="flex flex-row">
              <label class="mr-5">是否启用dropOut层</label>
              <el-switch v-model="form.dropOut" />
            </div>
          </el-form-item>
          <el-form-item label="">
            <div class="flex flex-col">
              <label>DropOut层P值</label>
              <el-input :disabled="!form.dropOut" @change="hanledropOutVal" type="number" min="0" step="0.1" max="1"
                v-model="form.dropOutVal" />
            </div>
          </el-form-item>
        </el-form>
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="addDialog = false">取消</el-button>
            <el-button type="primary" @click="sureAdd">添加</el-button>
          </span>
        </template>
      </el-dialog>

      <el-dialog v-model="addDialog2" title="隐藏层列表">
        <div class="deleteBtn p-5 -mt-6">
          <el-button type="default" @click="deleteData">删除所选隐藏层</el-button>
        </div>
        <el-table :data="hiddenLayer" class="!w-full" ref="tableRef1">
          <el-table-column type="selection" width="55" />
          <el-table-column type="index" width="50" />
          <el-table-column align="center" property="num" label="层节点数" />
          <el-table-column align="center" property="active" label="激活层">
            <template #default="scope">
              {{ scope.row.active.flag ? scope.row.active.val : '-' }}
            </template>
          </el-table-column>
          <el-table-column align="center" property="dropout" label="dropout层P值">
            <template #default="scope">
              {{ scope.row.dropout.flag ? scope.row.dropout.val : '-' }}
            </template>
          </el-table-column>
        </el-table>
      </el-dialog>
    </div>

    <div class="bt2" w-full h-full gap-2>
      <div class="css_canss" style="width: 60%" h-full>
        <div id="graph-container" class=" relative">
          <!-- <div class="fixed3"></div> -->
        </div>
      </div>
      <div class="tuxing" flex-1 h-full>
        <!-- echarts容器 -->
        <div h-full w-full bg-white ref="trainMain" id="main"></div>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
@import "@/styles/modelTrain.scss";

:deep(.fixed3) {
  position: absolute;
  left: 50%;
  bottom: 10px;
  width: 50%;
  transform: translateX(-50%);
  border: 1px solid #ccc;
  box-shadow: 0 0 5px #ccc;
  text-align: center;
  font-size: 14px;
}

.el-form--inline .el-form-item {
  margin-right: 0px;
}

.el-checkbox:last-of-type {
  margin-right: 30px;
}

.autoWidth {
  min-width: 195px;
  position: relative;

  :deep(.el-input__wrapper) {
    position: relative;
    box-sizing: border-box;
    border: 1px solid #ffffff00;
    height: 28px;
    line-height: 28px;

    .el-input__prefix {
      visibility: hidden;
    }

    .el-input__inner {
      position: absolute;
      left: 7px;
    }
  }

}



:deep(#graph-container) {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;

  svg {
    width: 100%;
    height: 100%;
    position: relative;
  }
}
</style>
